package com.my.reggie.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.my.reggie.common.R;
import com.my.reggie.config.WxPayConfig;
import com.my.reggie.enums.wxpay.WxTradeState;
import com.my.reggie.pojo.Orders;
import com.my.reggie.service.WxPayService;
import com.my.reggie.util.HttpUtils;
import com.my.reggie.util.WechatPay2ValidatorForRequest;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;

@Slf4j
@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付API")
public class WxPayController {
    @Resource
    private WxPayService wxPayService;
    @Resource
    private WxPayConfig wxPayConfig;
    @Resource
    private Verifier verifier;

    @PostMapping("/native")
    @ApiOperation("调用统一下单API，生成支付二维码")
    public R<Map> nativePay(@RequestBody Orders orders, HttpSession session) throws IOException {
        log.info("发起支付请求");

        //返回支付二维码和订单号
        Map body = wxPayService.nativePay(orders, session);
        if(body != null) {
            return R.success(body);
        } else {
            return R.error("获取支付信息失败!");
        }
    }

    /**
     * 用于前端定时查询支付状态
     * @param id
     * @return
     * @throws Exception
     */
    @ApiOperation("获取用户支付状态")
    @GetMapping("/getPayStatus/{id}")
    public R<String> getPayStatus(@PathVariable String id) throws Exception {
        log.info("向微信后台查询用户支付状态,订单号==>{}",id);

        String resultBody = wxPayService.queryOrder(id);
        JSONObject resultBodyJson = JSON.parseObject(resultBody);

        //获取订单支付状态
        String trade_state = (String) resultBodyJson.get("trade_state");

        //判断订单状态
        if(WxTradeState.SUCCESS.getType().equals(trade_state)) {
            //支付成功
            log.info("核实到已支付...");
            return R.success("支付成功");
        }
        //支付中
        R<String> r = new R<>();
        r.setCode(101);
        r.setMsg("支付中...");
        return r;
    }

    /**
     * 获取支付通知
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("支付回调通知")
    @PostMapping("/native/notify")
    public String getNativeNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("处理支付回调通知");
        Gson gson = new Gson();

        //应答体
        Map<String,String> map = new HashMap<>();
        try {
            //处理通知参数
            String body = HttpUtils.readData(request);
            JSONObject data = JSON.parseObject(body);

            //回调通知的验签与解密
            String wechatPaySerial = request.getHeader(WECHAT_PAY_SERIAL);
            String apiV3Key = wxPayConfig.getApiV3Key();
            String nonce = request.getHeader(WECHAT_PAY_NONCE); // 请求头Wechatpay-Nonce
            String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP); // 请求头Wechatpay-Timestamp
            String signature = request.getHeader(WECHAT_PAY_SIGNATURE); // 请求头Wechatpay-Signature
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(wechatPaySerial,apiV3Key,nonce, timestamp, signature, body,verifier);
            Notification notification = wechatPay2ValidatorForRequest.notificationHandler();
            String eventType = notification.getEventType();
            if(eventType.length() == 0){
                log.error("支付回调通知验签失败");
                response.setStatus(500);
                map.put("code","ERROR");
                map.put("message","失败");
                return gson.toJson(map);
            }

            log.info("支付回调通知验签成功");

            //处理订单
            wxPayService.processOrder(notification);

            //应答响应码(200或者204表示成功)
            response.setStatus(200);
            map.put("code","SUCCESS");
            map.put("message","成功");
            return gson.toJson(map);
        } catch (Exception e) {
            e.printStackTrace();
            response.setStatus(500);
            map.put("code","ERROR");
            map.put("message","失败");
            return gson.toJson(map);
        }
    }

    /**
     * 用户取消订单
     * @param order
     * @return
     */
    @ApiOperation("取消订单")
    @PostMapping("/cancel")
    public R<String> cancelOrder(@RequestBody Orders order) throws Exception {
        log.info("取消订单");
        wxPayService.cancelOrder(order);
        return R.success("取消订单成功");
    }

    /**
     * 查询订单
     * @param orderNo
     * @return
     */
    @ApiOperation("查询订单：查询订单测试使用")
    @GetMapping("/query/{orderNo}")
    public R<String> queryOrder(@PathVariable String orderNo) throws Exception {
        log.info("查询订单");
        String result = wxPayService.queryOrder(orderNo);
        return R.success(result);
    }

    /**
     * 订单退款
     * @param order
     * @return
     */
    @ApiOperation("退款申请")
    @PostMapping("/refund")
    public R<String> refund(@RequestBody Orders order) throws Exception {
        log.info("处理退款申请...");
        wxPayService.refund(order);
        return R.success("处理退款成功，订单正在退款中...");
    }

    /**
     * 获取退款通知
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("退款结果回调通知")
    @PostMapping("/refunds/notify")
    public String getRefundNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("处理退款结果回调通知...");
        Gson gson = new Gson();
        //应答体
        Map<String,String> map = new HashMap<>();
        try {
            //处理通知参数
            String body = HttpUtils.readData(request);

            //回调通知的验签与解密
            String wechatPaySerial = request.getHeader(WECHAT_PAY_SERIAL);
            String apiV3Key = wxPayConfig.getApiV3Key();
            String nonce = request.getHeader(WECHAT_PAY_NONCE); // 请求头Wechatpay-Nonce
            String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP); // 请求头Wechatpay-Timestamp
            String signature = request.getHeader(WECHAT_PAY_SIGNATURE); // 请求头Wechatpay-Signature
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(wechatPaySerial,apiV3Key,nonce, timestamp, signature, body,verifier);
            Notification notification = wechatPay2ValidatorForRequest.notificationHandler();
            log.info("notification===>{}",notification.toString());
            String eventType = notification.getEventType();
            if(eventType.length() == 0){
                log.error("退款结果回调通知验签失败");
                response.setStatus(500);
                map.put("code","ERROR");
                map.put("message","失败");
                return gson.toJson(map);
            }
            log.info("退款结果回调通知验签成功");

            //处理订单
            wxPayService.processRefund(notification);

            //应答响应码(200或者204表示成功)
            response.setStatus(200);
            map.put("code","SUCCESS");
            map.put("message","成功");
            return gson.toJson(map);
        } catch (Exception e) {
            e.printStackTrace();
            response.setStatus(500);
            map.put("code","ERROR");
            map.put("message","失败");
            return gson.toJson(map);
        }
    }
}
